-- 年度投票更新
local mis_uu = require('modules.commhm.utils')
local mis_env = require('modules.env.env')
local mis_timer = require('modules.commhm.ngxTimerWrap')
local uu = mis_uu
local tonumber = tonumber
local os_date = os.date
local string_match = string.match

local ngx = ngx

local mis_log = nil
local mis_config = nil
local mis_data = nil
local mis_common = nil
local mis_bridge = nil
local mis_calcu = nil
local t_retCode = nil

-- shareDict缓存
local t_cache = ngx.shared.misAnnualVote

-- local s_workerid = "_" .. ngx.worker.id()
local s_workerid = ""

--------------------------------------------------------------
local mis_annualVote = {
	s_name = string.match(debug.getinfo(1).short_src, '.*/(.*).lua');	-- 模块名称
}
local this = mis_annualVote


local function update_vote(s_type)
	local s_voteAll = s_type .. "_voteAll"
	local n_code, s_desc, t_voteAll, t_voteSum, b_ok
	local s_keyLocal, s_keyRemote, n_voteLocal, n_voteRemote, s_err
	local t_conf = mis_data.t_share_mission[s_type]
	local n_now = mis_data.offset_now_v2(t_conf)
	local t_sysUser = mis_data.get_user(0)

	repeat
		if not t_conf then
			mis_log.day('annualVote', s_type .. ' config empty: ' .. uu.to_str(t_conf))
			return false
		end

		if t_conf.n_status ~= mis_config.t_workStatus.n_ENABLE then
			-- 如果活动已经结束，则退出票数统计
			if t_conf.t_conf.n_endTime and (t_conf.t_conf.n_endTime + 60) < n_now then
				mis_log.day('annualVote', s_type .. 'disable and out of time!')
				return false
			end

			mis_log.day('annualVote', s_type .. ' disable! status: ' .. uu.to_str(t_conf and t_conf.n_status))
			break
		end

		if t_conf.t_conf.n_startTime and n_now < t_conf.t_conf.n_startTime then
			mis_log.day('annualVote', s_type .. 'not start!')
			break
		end

		-- 如果活动已经结束，则不需继续统计
		if t_conf.t_conf.n_endTime and (t_conf.t_conf.n_endTime + 60) < n_now then
			mis_log.day('annualVote', s_type .. 'out of time!')
			break
		end

		n_code, t_voteAll = t_sysUser:get_share_mission_data(mis_config.t_workType.s_ANNUAL_VOTE, false, true)
		if n_code ~= t_retCode.n_OK then
			mis_log.day('annualVote_error', "get_share_mission_data error|" .. s_type .. '|' .. n_code .. "|" .. uu.to_str(t_voteAll))
			break
		end

		t_voteAll[s_type] = t_voteAll[s_type] or {}

		-- 本地投票数更新到ssdb
		for k, v in pairs(t_conf.t_conf.t_candidate) do
			s_keyLocal = s_type .. k .. s_workerid
			n_voteLocal, s_err = t_cache:get(s_keyLocal)
			if s_err then
				mis_log.day('annualVote_error', "shareDict get error|" .. s_type .. '|' .. s_keyLocal .. "|" .. uu.to_str(s_err))
			end

			n_voteLocal = tonumber(n_voteLocal) or 0
			s_keyRemote = k .. "_" .. mis_env.host_id .. s_workerid
			n_voteRemote = t_voteAll[s_type][s_keyRemote] or 0

			-- mis_log.day("update_vote", mis_uu.to_str(s_keyLocal) .. "|" .. mis_uu.to_str(n_voteLocal) .. "|" .. mis_uu.to_str(n_voteRemote) .. "|" .. mis_uu.to_str(s_err))

			if n_voteLocal > n_voteRemote then
				t_voteAll[s_type][s_keyRemote] = n_voteLocal
			elseif n_voteLocal < n_voteRemote then
				mis_log.day('annualVote', "supply warn|" .. s_type .. '|' .. k .. "|" .. n_voteLocal .. "|" .. n_voteRemote)
				n_code, n_voteLocal = this.vote(s_type, k, n_voteRemote)
				if n_code == t_retCode.n_OK then
					t_voteAll[s_type][s_keyRemote] = n_voteLocal
				end
			end
		end

		-- 写入ssdb
		n_code, s_desc = t_sysUser:set_share_mission_data(mis_config.t_workType.s_ANNUAL_VOTE, t_voteAll)
		if n_code ~= t_retCode.n_OK then
			mis_log.day('annualVote_error', "set_share_mission_data error|" .. s_type .. '|' .. n_code .. '|' .. s_desc .. "|" .. uu.to_str(t_voteAll))
		end

		-- 写入共享缓存
		b_ok, s_err = t_cache:set(s_voteAll, mis_common.table_to_string(t_voteAll))
		if not b_ok then
			mis_log.day('annualVote_error', "shareDict set error|" .. s_type .. '|' .. s_voteAll .. "|" .. uu.to_str(s_err) .. "|" .. uu.to_str(t_voteAll))
		end

	until true

	mis_log.day('annualVote', s_workerid .. "|" .. s_type .. ' update vote:' .. ' t_voteAll:' .. uu.to_str(t_voteAll))

	return true
end

--------------------------------------------------------------
-- 说明：定期更新投票数
local function update_vote_loop()
	local continue = false

	continue = update_vote(mis_config.t_workType.s_CONTEST_MAP) or continue
	continue = update_vote(mis_config.t_workType.s_CONTEST_VIDEO) or continue
	continue = update_vote(mis_config.t_workType.s_CONTEST_SOCIAL) or continue

	mis_log.day('annualVote', s_workerid .. ' loop! now: ' .. uu.now())

	if continue then
		mis_timer:new():ngx_timer_at(mis_config.n_annualVoteInterval, update_vote_loop)
	end
end

--------------------------------------------------------------
-- 说明：模块包含
-- 参数：模块表
this.modules_include = function(t_moddules)
	mis_log = t_moddules.mis_log
	mis_config = t_moddules.mis_config
	mis_data = t_moddules.mis_data
	mis_common = t_moddules.mis_common
	mis_bridge = t_moddules.mis_bridge
	mis_calcu = t_moddules.mis_calcu
	t_retCode = mis_config.t_retCode
end

--------------------------------------------------------------
-- 说明：load级初始化
this.init_load = function()
	mis_log.day('annualVote', 'init_load! worker ' .. ngx.worker.id())
	-- if mis_calcu.is_master_server() == true then
	if true then
		-- 开启循环
		-- if #s_workerid > 0 or t_cache:add("annualVoteTimerLock", 1, 10) then
		if #s_workerid > 0 or ngx.worker.id() == 0 then
			local _, s_err = mis_timer:new():ngx_timer_at(mis_config.n_annualVoteInterval, update_vote_loop)
			if s_err then
				return t_retCode.n_SYS_ERR, 'start ngx.timer.every failed, ' .. s_err
			else
				mis_log.day('annualVote', 'start! ' .. s_workerid .. ", worker " .. ngx.worker.id())
			end
		else
			mis_log.day('annualVote', 'not got lock! ' .. s_workerid .. ", worker " .. ngx.worker.id())
		end
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：投票
-- 参数：s_type 业务类型
-- 参数：uin 用户迷你号
-- 参数：count 投票数量
this.vote = function(s_type, n_uin, n_count)
	local s_keyLocal = s_type .. n_uin .. s_workerid
	local n_v, s_err = t_cache:incr(s_keyLocal, n_count, 0)
	if s_err then
		mis_log.day('annualVote_error', 'incr shared dict misAnnualVote failed.' .. "|" .. s_keyLocal .. "|" .. n_count)
		return t_retCode.n_DB_ERR, s_err
	end
	return t_retCode.n_OK, n_v
end

--------------------------------------------------------------
-- 说明：获取某个业务下的投票总数
-- 参数：uin 用户迷你号，如果不传则返回全部数据
local get_vote_sum = function(s_type)
	local t_voteAll
	local s_voteAll = s_type .. "_voteAll"
	local s_data, s_err = t_cache:get(s_voteAll)
	if not s_data then
		mis_log.day('annualVote_error', 'get shared dict misAnnualVote failed.' .. "|" .. s_voteAll)
		t_voteAll = {}
	else
		t_voteAll = mis_common.string_to_table(s_data)
		if not t_voteAll then
			mis_log.day('annualVote_error', 'string_to_table failed.' .. "|" .. s_voteAll .. "|" .. s_data)
			t_voteAll = {}
		end
	end

	local t_voteSType = t_voteAll[s_type]
	if not t_voteSType then
		mis_log.day('annualVote_error', 'no vote data.' .. "|" .. s_type .. "|" .. mis_uu.to_str(t_voteAll))
		t_voteSType = {}
	end

	-- 所有服务器的累计票数
	local t_voteSum = {}
	local s_keyLocal, n_voteLocal, s_keyRemote, s_err, n_k
	for k, v in pairs(t_voteSType) do
		n_k = tonumber(string_match(k, "^(%d+)_.+"))
		if n_k then
			-- 本地和远程的对比取大值
			s_keyRemote = n_k .. "_" .. mis_env.host_id .. s_workerid
			if s_keyRemote == k then
				s_keyLocal = s_type .. n_k .. s_workerid
				n_voteLocal, s_err = t_cache:get(s_keyLocal)
				if n_voteLocal and tonumber(n_voteLocal) > v then
					v = tonumber(n_voteLocal)
				end
			end
			t_voteSum[n_k] = (t_voteSum[n_k] or 0) + v
		else
			mis_log.day('annualVote_error', 'vote remote key error.' .. "|" .. s_type .. "|" .. mis_uu.to_str(k) .. "|" .. mis_uu.to_str(v))
		end
	end

	-- 优化日志输出
	if ngx.ctx.t_params and (ngx.ctx.t_params.uin == 1159398778 or ngx.ctx.t_params.uin == 1000042652) then
		mis_log.day("get_vote_data", 'vote all ' .. s_workerid .. "|" .. s_type .. "|" .. mis_uu.to_str(t_voteSum) .. "|" .. mis_uu.to_str(t_voteAll) .. "|" .. mis_uu.to_str(s_data))
	end

	return t_retCode.n_OK, t_voteSum
end

--------------------------------------------------------------
-- 说明：获取投票数据
-- 参数：uin 用户迷你号，如果不传则返回全部数据
this.get_vote_data = function(s_type, n_uin)
	-- 所有服务器的累计票数
	local n_code, t_voteSum = get_vote_sum(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_voteSum
	end
	local t_conf = mis_data.t_share_mission[s_type].t_conf
	if n_uin then
		local n_vote = t_voteSum[n_uin]
		if n_vote == nil then
			local s_keyLocal = s_type .. n_uin .. s_workerid
			local n_voteLocal, s_err = t_cache:get(s_keyLocal)
			n_vote = tonumber(n_voteLocal) or 0
		end
		return t_retCode.n_OK, n_vote + (t_conf.t_candidate[n_uin] or 0)
	else
		local s_keyLocal, n_voteLocal, s_err
		for k, v in pairs(t_conf.t_candidate) do
			if t_voteSum[k] then
				t_voteSum[k] = t_voteSum[k] + v
			else
				s_keyLocal = s_type .. k .. s_workerid
				n_voteLocal, s_err = t_cache:get(s_keyLocal)
				t_voteSum[k] = (tonumber(n_voteLocal) or 0) + v
			end
		end
		return t_retCode.n_OK, t_voteSum
	end
end

return this